import requests
import redis
import random
from PIL import Image
import io
from io import BytesIO
import os
import base64
import time
from bs4 import BeautifulSoup
import numpy as np

# redis 初始化
redis_server = redis.StrictRedis(host='localhost', port=6379, db=0, decode_responses=True)


# 通用登录
def user_login(user, pwd):
    res = {
        'code': 0,
        'msg': "",
        'score': 0
    }
    global redis_server
    pwd_redis = redis_server.get("user_" + user)
    if pwd_redis is not None:
        if pwd_redis == pwd:
            user_score = redis_server.hget("score_list", user)
            if user_score is not None:
                res['score'] = user_score
            return res
        else:
            res['msg'] = "密码有误"
            res['code'] = 2
            return res
    else:
        redis_server.set("user_" + user, pwd)
        res['msg'] = "注册成功"
        return res


# 从MCPro爬虫获取卡片数据
def fetch_api_data():
    url = 'https://sapi.moecube.com:444/ygopro/analytics/single/type?type=month&lang=cn&extra=name&source=mycard-athletic'
    try:
        response = requests.get(url)
        response.raise_for_status()  # 检查是否出现HTTP错误
        data = response.json()  # 获取JSON格式的响应数据
        return data
    except requests.exceptions.RequestException as error:
        print("获取MCPro卡片数据失败:", error)
        return None


def clear_score():
    # 月初积分掉段
    global redis_server
    now_day = time.localtime(time.time()).tm_mday
    if now_day == 1:
        rank_dict = redis_server.hgetall("score_list")
        rank_user_items = rank_dict.items()
        rank_data_level_down = {}
        for item in rank_user_items:
            user_name = item[0]
            user_score = int(item[1])
            # 按照当前段位掉一段
            if user_score < 100:
                user_score = 0
            elif user_score < 300:
                user_score = 100
            elif user_score < 800:
                user_score = 300
            elif user_score < 1500:
                user_score = 800
            else:
                user_score = 1500
            rank_data_level_down[user_name] = user_score
        # 更新积分
        redis_server.hmset("score_list", rank_data_level_down)
        del rank_dict, rank_data_level_down


# 获取两个列表的交集
def inter(a, b):
    return list(set(a) & set(b))


# 生成随机数(包含除外数)
def my_custom_random(exclude):
    rand_num = np.random.randint(0, 3, 1)
    # 0和9之间随机生成两个不同的数字
    return my_custom_random(exclude) if inter(rand_num, exclude) else rand_num


def card_data_refresh(fetch_data, date_old):
    # 每2个小时清空一次爬取数据
    now_time = time.time()
    if now_time - date_old > 2 * 60 * 60:
        fetch_data = None
        date_old = now_time

    api_result = fetch_data if fetch_data is not None else fetch_api_data()

    # 随机从“怪兽”、“魔法”、“陷阱”、“额外”之中选择一类卡片数据，排除“卡组”大类
    card_type = ["monster", "spell", "trap", "ex"]
    selected_category = random.choice(card_type)
    selected_card_list = api_result[selected_category]
    card_account = len(api_result[selected_category])

    # 从已选大类中随机选择一张卡片，获取卡片id
    while True:
        card_number = random.randint(0, card_account - 1)
        selected_card = selected_card_list[card_number]
        card_id = selected_card['id']
        break

        # # 从另一个接口获取卡片的发售日
        # card_date_url = "https://ygocdb.com/card/" + str(card_id)
        # card_date_response = requests.get(card_date_url)
        # card_date_htmltext = card_date_response.text
        # soup = BeautifulSoup(card_date_htmltext, 'html.parser')
        # date_spans = soup.find_all('span', class_='pack')

        # for date_span in date_spans:
        #     date_info = date_span.text.strip()
        #     date_index = date_info.find('(')
        #     if date_index != -1:
        #         date = date_info[date_index + 1: -1]
        #     else:
        #         print("未找到日期")

        # # 将提取的日期信息转换为日期对象
        # date_from_html = date
        # date_object = datetime.strptime(date_from_html, "%Y-%m-%d")

        # # 比较日期是否晚于去年的今天
        # current_date = datetime.now()
        # last_year_today = current_date - timedelta(days=365)
        # if date_object > last_year_today:
        #     # print("本次找到的卡片发售距今不足一年，将重新选择。附本次日期：", date)
        #     True
        # else:
        #     break
    # print("随机选择的卡片:")
    # print("ID:", card_id)

    # 获取卡片的五种译名
    card_name_url = "https://ygocdb.com/card/" + str(card_id)  # 暂时没找到更方便的网站
    card_name_response = requests.get(card_name_url)
    card_name_htmltext = card_name_response.text
    soup = BeautifulSoup(card_name_htmltext, 'html.parser')

    card_name_ygopro_tag = soup.find('th', string='YGOPro译名')
    card_name_ygopro = card_name_ygopro_tag.find_next('span').text
    card_name_cnoffical_tag = soup.find('th', string='简中官方译名')
    card_name_cnoffical = card_name_cnoffical_tag.find_next('span').text
    card_name_md_tag = soup.find('th', string='Master Duel译名')
    card_name_md = card_name_md_tag.find_next('span').text
    card_name_nwbbs_tag = soup.find('th', string='NWBBS译名')
    card_name_nwbbs = card_name_nwbbs_tag.find_next('span').text
    card_name_cnocg_tag = soup.find('th', string='CNOCG译名')
    card_name_cnocg = card_name_cnocg_tag.find_next('span').text
    # print("五种译名分别为：", card_name_ygopro, card_name_cnoffical, card_name_md, card_name_nwbbs, ard_name_cnocg)

    # 获取图片的互联网地址
    cardpic_url = "https://cdn.233.momobako.com/ygopro/pics/" + str(card_id) + ".jpg"
    # print("卡图网址:", cardpic_url)

    # 发送请求获取图片内容
    response = requests.get(cardpic_url)
    cardpic_data = response.content

    # 将卡图内容加载到Pillow Image对象中，并保存到本地
    cardpic_image = Image.open(BytesIO(cardpic_data))
    folder_path = "picture/"
    if not os.path.exists(folder_path):
        os.mkdir(folder_path)
    cardpic_image.save(os.path.join(folder_path, card_name_cnocg + ".jpg"))

    # 获取图片的宽度和高度
    width_origin, height_origin = cardpic_image.size

    # 计算实际卡图的边长（除灵摆卡外，卡图为正方形，边长为整张卡宽度的四分之三）
    width = width_origin * 3 / 4

    # 已知卡图区域宽度占整张卡宽度的四分之三，再取三分之一作为裁剪区域边长
    cut_width = width / 3

    # 随机选择裁剪区域的起始点
    # start_x = 0.125 * width_origin + random.randint(0, 2) * sixteenth_width   #将图片均分为九宫格，任取一格的左上顶点横坐标
    # start_y = 0.181 * height_origin + random.randint(0, 2) * sixteenth_width #将图片均分为九宫格，任取一格的左上顶点纵坐标

    local_x = random.randint(0, 2)
    local_y = random.randint(0, 2)
    start_x = 0.125 * width_origin + local_x * cut_width  # 将图片均分为九宫格，任取左上方四格的任意一点作为裁剪区域的起点，获取这一点的横坐标
    start_y = 0.181 * height_origin + local_y * cut_width  # 将图片均分为九宫格，任取左上方四格的任意一点作为裁剪区域的起点，获取这一点的纵坐标

    # 计算裁剪区域的结束点
    end_x = start_x + cut_width
    end_y = start_y + cut_width

    # 裁剪图片，尺寸为原图的九分之一
    cut_image = cardpic_image.crop((start_x, start_y, end_x, end_y))

    # 保存裁剪后的图像
    # folder_path = "picture/"
    # if not os.path.exists(folder_path):
    #     os.mkdir(folder_path)
    # timestamp = str(int(time.time()))
    # cut_image.save(os.path.join(folder_path, card_name_cnocg + "_" + timestamp + ".jpg"))

    # 将图像转换为BytesIO对象
    cut_image_bytes = io.BytesIO()
    cut_image.save(cut_image_bytes, format='JPEG')
    cut_image_bytes.seek(0)

    # 将BytesIO对象转换为Base64编码
    cut_image_base64 = base64.b64encode(cut_image_bytes.read()).decode('utf-8')
    # print("题面图片base64：", cut_image_base64)

    # 提示1：卡片类型
    if selected_category == "monster" or "ex":
        tip1 = "卡片类型是怪兽卡"
    if selected_category == "spell":
        tip1 = "卡片类型是魔法卡"
    if selected_category == "trap":
        tip1 = "卡片类型是陷阱卡"
    # print(tip1)

    # 提示2：卡名中的随机一位字符，如果是空格则取下一位
    character_no = random.randint(0, len(card_name_nwbbs) - 1)
    character = card_name_nwbbs[character_no] if ((card_name_nwbbs[character_no] != ' ')
                                                  and (card_name_nwbbs[character_no] != '-')
                                                  and (card_name_nwbbs[character_no] != '▪')) else card_name_nwbbs[
        character_no + 1]
    tip2 = "卡名中包含" + "“" + character + "”字样"
    # print(tip2)

    # 提示3：更大的截图区域（将卡图分为四宫格，裁剪上次起点所在的那一格图像，即卡图的四分之一）
    '''
    if start_x <= 0.125 * width_origin + 0.5 * width and start_y <= 0.181 * height_origin + 0.5 * width:
        tip3_cut_image = cardpic_image.crop((
            0.125 * width_origin, 0.181 * height_origin, 0.125 * width_origin + 0.5 * width,
            0.181 * height_origin + 0.5 * width))
    if start_x <= 0.125 * width_origin + 0.5 * width and start_y > 0.181 * height_origin + 0.5 * width:
        tip3_cut_image = cardpic_image.crop((0.125 * width_origin, 0.181 * height_origin + 0.5 * width,
                                             0.125 * width_origin + 0.5 * width, 0.181 * height_origin + width))
    if start_x > 0.125 * width_origin + 0.5 * width and start_y <= 0.181 * height_origin + 0.5 * width:
        tip3_cut_image = cardpic_image.crop((0.125 * width_origin + 0.5 * width, 0.181 * height_origin,
                                             0.125 * width_origin + width, 0.181 * height_origin + 0.5 * width))
    if start_x > 0.125 * width_origin + 0.5 * width and start_y > 0.181 * height_origin + 0.5 * width:
        tip3_cut_image = cardpic_image.crop((0.125 * width_origin + 0.5 * width, 0.181 * height_origin + 0.5 * width,
                                             0.125 * width_origin + width, 0.181 * height_origin + width))
    '''
    local_x_tip3 = my_custom_random([local_x])[0]
    local_y_tip3 = my_custom_random([local_y])[0]
    start_x_tip3 = 0.125 * width_origin + local_x_tip3 * cut_width  # 将图片均分为九宫格，任取左上方四格的任意一点作为裁剪区域的起点，获取这一点的横坐标
    start_y_tip3 = 0.181 * height_origin + local_y_tip3 * cut_width  # 将图片均分为九宫格，任取左上方四格的任意一点作为裁剪区域的起点，获取这一点的纵坐标

    tip3_cut_image = cardpic_image.crop(
        (start_x_tip3, start_y_tip3, start_x_tip3 + cut_width, start_y_tip3 + cut_width))

    tip3_cut_image_bytes = io.BytesIO()
    tip3_cut_image.save(tip3_cut_image_bytes, format='JPEG')
    tip3_cut_image_bytes.seek(0)

    # 将BytesIO对象转换为Base64编码
    tip3 = base64.b64encode(tip3_cut_image_bytes.read()).decode('utf-8')
    # print("提示3图片base64：", tip3)

    # 将所有所需元素合并为一个json输出
    data = {
        "cut_pic": cut_image_base64,  # 裁剪后的卡图的base64编码，作为题面
        "x": local_x, "y": local_y,
        "origin_pic": cardpic_url,  # 原始卡图的网络地址，答题后展示
        "card_name_ygopro": card_name_ygopro,  # ygopro译名，用于比对用户答案、答题后展示
        "card_name_cnoffical": card_name_cnoffical,  # j简中官方译名，用于比对用户答案
        "card_name_md": card_name_md,  # MasterDuel译名，用于比对用户答案
        "card_name_nwbbs": card_name_nwbbs,  # nwbbs译名，用于比对用户答案
        "card_name_cnocg": card_name_cnocg,  # cnocg译名，用于比对用户答案
        "tip1": tip1,  # 提示1（卡片类型，文本）
        "tip2": tip2,  # 提示2（卡名中的任意一个非空字符，文本）
        "tip3": tip3,  # 提示3（图片base64编码）
        "x_tip3": int(local_x_tip3), "y_tip3": int(local_y_tip3),
    }
    return data


# 获取排名数据
def rank_data(user, inc):
    res = {}
    # 获取当前玩家积分
    score_str = redis_server.hget("score_list", user) or 0
    score = int(score_str) + int(inc)
    redis_server.hset("score_list", user, score)
    res['score'] = score
    # 获取所有玩家排名
    rank_dict = redis_server.hgetall("score_list")
    rank_result = sorted(rank_dict.items(), key=lambda x: int(x[1]), reverse=True)
    res['list'] = rank_result
    return res
